package com.micro;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;


public class CompressNumberStringTester {
    private static final char []EXCLUSIVE_CHARS = { '%', '\'', '_' };
    private static char []INCLUSIVE_CHARS;
    public static int MAX_RADIX = 94;
    static {
        Arrays.sort(EXCLUSIVE_CHARS);
        INCLUSIVE_CHARS = new char[EXCLUSIVE_CHARS.length];
        for (int i = 0; i < EXCLUSIVE_CHARS.length; ++i) {
            INCLUSIVE_CHARS[i] = (char) (126 - i);
        }
        MAX_RADIX -= EXCLUSIVE_CHARS.length + 1;
    }
    public static final int MIN_CHAR_CODE = 34;
    public static final char LEFT_PAD_CHAR = '!';
    
    /**
        !    "    #    $    %    &    '    (    )    *
        +    ,    -    .    /    0    1    2    3    4
        5    6    7    8    9    :    ;    <    =    >
        ?    @    A    B    C    D    E    F    G    H
        I    J    K    L    M    N    O    P    Q    R
        S    T    U    V    W    X    Y    Z    [    \
        ]    ^    _    `    a    b    c    d    e    f
        g    h    i    j    k    l    m    n    o    p
        q    r    s    t    u    v    w    x    y    z
        {    |    }    ~
     * 其中!%_'被占用，计算策略：
     * !被忽略
     * 当字符为%，则用~代替
     * 当字符为_，则用}代替
     * 当字符为'，则用|代替
     * 依次类推。。。。。。
     */

    public static String toString(long num, int radix) {
        if (num < 0L) {
            throw new IllegalArgumentException("negative long number is not supported!");
        }
        if (radix < 2 || radix > MAX_RADIX) {
            throw new IllegalArgumentException("radix " + radix + " is not supported!");
        }
        if (num == 0L) {
            return "0";
        }
        int len = getLength(radix);
        
        char chars[] = new char[len];  // String.valueOf(Long.MAX_VALUE).length() => 19
        int idx = chars.length - 1;
        long tmp;
        // 32是空白符，33至126是ASCII码字符
        // 0~9是数字
        char temp;
        do {
            tmp = num % radix;
            temp = (char)(tmp + MIN_CHAR_CODE);
            for (int i = 0; i < EXCLUSIVE_CHARS.length; ++i) {
                if (EXCLUSIVE_CHARS[i] == temp) {
                    temp = INCLUSIVE_CHARS[i];
                    break;
                }
            }
            chars[idx--] = temp;
            num = num / radix;
        } while (num > 0L);
        
        if (idx >= 0) {
            Arrays.fill(chars, 0, idx + 1, LEFT_PAD_CHAR);
        }
        
        return new String(chars);
    }
    
    public static long toLong(String str, int radix) {
        if (radix < 2 || radix > MAX_RADIX) {
            throw new IllegalArgumentException("radix " + radix + " is not supported!");
        }
        long value = 0L;
        int size = str.length();
        long radix0 = 1L;
        for (int i = size - 1; i >= 0; --i) {
            char ch = str.charAt(i);
            if (LEFT_PAD_CHAR == ch) { break; }
            if (ch < MIN_CHAR_CODE || ch > 126) {
                throw new IllegalArgumentException("the string contains illegal characters!");
            }
            for (int j = 0; j < INCLUSIVE_CHARS.length; ++j) {
                if (ch == INCLUSIVE_CHARS[j]) {
                    ch = EXCLUSIVE_CHARS[j];
                    break;
                }
            }
            value += (ch - MIN_CHAR_CODE) * radix0;
            
            radix0 *= radix;
        }
        return value;
    }
    
    public static int toInt(String str, int radix) {
        if (radix < 2 || radix > MAX_RADIX) {
            throw new IllegalArgumentException("radix " + radix + " is not supported!");
        }
        if (str == null) {
            return -1;
        }
        int value = 0;
        int size = str.length();
        int radix0 = 1;
        for (int i = size - 1; i >= 0; --i) {
            char ch = str.charAt(i);
            if (LEFT_PAD_CHAR == ch) { break; }
            if (ch < MIN_CHAR_CODE || ch > 126) {
                throw new IllegalArgumentException("the string contains illegal characters!");
            }
            
            for (int j = 0; j < INCLUSIVE_CHARS.length; ++j) {
                if (ch == INCLUSIVE_CHARS[j]) {
                    ch = EXCLUSIVE_CHARS[j];
                    break;
                }
            }
            
            value += (ch - MIN_CHAR_CODE) * radix0;
            radix0 *= radix;
        }
        return value;
    }
    
    public static String toStringAsRadixIs1024(long num) {
        if (num < 0L) {
            throw new IllegalArgumentException("negative long number is not supported!");
        }
        if (num == 0L) {
            return "0";
        }
        int len = 11;
        
        char chars[] = new char[len];  // String.valueOf(Long.MAX_VALUE).length() => 19
        int idx = chars.length - 1, radix = 64, log = 6;
        long tmp;
        do {
//            tmp = num - ((num >> 10) << 10);
            tmp = num & (radix - 1);
            chars[idx--] = (char)(tmp + 33);
            num >>= log;
        } while (num > 0L);
        
        return new String(chars, idx + 1, chars.length - idx - 1);
    }
    
    public static int getLength(int radix) {
        int len = 10;
        if (radix == 2) { len = 63; }
        else if (radix == 3) { len = 40; }
        else if (radix == 4) { len = 32; }
        else if (radix <= 7) { len = 28; }
        else if (radix <= 9) { len = 21; }
        else if (radix <= 22) { len = 19; }
        else if (radix <= 28) { len = 14; }
        else if (radix <= 38) { len = 13; }
        else if (radix <= 52) { len = 12; }
        else if (radix <= 78) { len = 11; }
        return len;
    }
    
    
    public static void main(String[] args) throws Exception {

    }
	
}
